/**
 * HTTP 请求客户端配置文件
 *
 * 该文件主要负责：
 * 1. 创建和配置 HTTP 请求客户端
 * 2. 处理请求和响应拦截
 * 3. 实现认证和刷新令牌逻辑
 * 4. 统一错误处理
 */

import type { RequestClientOptions } from '@vben/request';

// 导入必要的工具和组件
import { useAppConfig } from '@vben/hooks';           // 应用配置 Hook
import { preferences } from '@vben/preferences';      // 应用偏好设置
import {
  authenticateResponseInterceptor,                    // 认证响应拦截器
  defaultResponseInterceptor,                         // 默认响应拦截器
  errorMessageResponseInterceptor,                    // 错误消息响应拦截器
  RequestClient,                                      // 请求客户端类
} from '@vben/request';
import { useAccessStore } from '@vben/stores';        // 访问令牌存储

import { ElMessage } from 'element-plus';             // Element Plus 消息组件

import { useAuthStore } from '#/store';               // 认证状态存储
import { refreshTokenApi } from './core';             // 刷新令牌 API

// 从环境变量中获取 API URL
const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD);

/**
 * 创建请求客户端实例
 * @param baseURL - API 基础URL
 * @param options - 请求客户端配置选项
 * @returns 配置好的请求客户端实例
 */
function createRequestClient(baseURL: string, options?: RequestClientOptions) {
  // 创建请求客户端实例
  const client = new RequestClient({
    ...options,
    baseURL,
  });

  /**
   * 重新认证处理函数
   * 当访问令牌或刷新令牌无效/过期时调用
   *
   * 处理流程：
   * 1. 清除当前访问令牌
   * 2. 根据配置显示登录过期模态框或提示信息
   * 3. 等待用户手动操作
   */
  async function doReAuthenticate() {
    console.warn('Access token or refresh token is invalid or expired.');
    const accessStore = useAccessStore();
    const authStore = useAuthStore();
    accessStore.setAccessToken(null);

    if (preferences.app.loginExpiredMode === 'modal' && accessStore.isAccessChecked) {
      accessStore.setLoginExpired(true);
    } else {
      console.log('doReAuthenticate');
      // 显示提示框，告知用户需要重新登录

      // 不要立即调用 logout，等待用户手动操作
      //  await authStore.logout();
    }
  }

  /**
   * 刷新令牌处理函数
   *
   * 处理流程：
   * 1. 调用刷新令牌 API
   * 2. 更新存储中的访问令牌
   * 3. 返回新的访问令牌
   *
   * @returns 新的访问令牌
   * @throws 刷新失败时抛出错误
   */
  async function doRefreshToken() {
    const accessStore = useAccessStore();
    try {
      const resp = await refreshTokenApi();
      if (resp.status === 200) {
        accessStore.setAccessToken(resp.data);
        accessStore.setRefreshToken(resp.refreshToken);
        return resp.data;
      } else {
        throw new Error('刷新令牌失败');
      }
    } catch (error) {
      accessStore.setAccessToken(null);
      accessStore.setRefreshToken(null);
      throw error;
    }
  }

  /**
   * 格式化令牌
   * 添加 Bearer 前缀
   *
   * @param token - 原始令牌
   * @returns 格式化后的令牌或 null
   */
  function formatToken(token: null | string) {
    return token ? `Bearer ${token}` : null;
  }

  /**
   * 请求拦截器配置
   * 在发送请求前：
   * 1. 添加认证头
   * 2. 添加语言偏好
   */
  client.addRequestInterceptor({
    fulfilled: async (config) => {
      const accessStore = useAccessStore();

      config.headers.Authorization = formatToken(accessStore.accessToken);
      config.headers['Accept-Language'] = preferences.app.locale;
      return config;
    },
  });

  /**
   * 响应拦截器配置
   *
   * 1. 默认响应处理：统一响应数据格式
   * 2. 认证响应处理：处理令牌相关逻辑
   * 3. 错误响应处理：统一错误提示
   */

  // 处理返回的响应数据格式
  client.addResponseInterceptor(
    defaultResponseInterceptor({
      codeField: 'code',          // 状态码字段名
      dataField: 'data',          // 数据字段名
      successCode: 'SUCCESS',     // 成功状态码
    }),
  );

  // 处理令牌过期
  client.addResponseInterceptor(
    authenticateResponseInterceptor({
      client,                     // 请求客户端实例
      doReAuthenticate,           // 重新认证处理函数
      doRefreshToken,            // 刷新令牌处理函数
      enableRefreshToken: preferences.app.enableRefreshToken,  // 是否启用令牌刷新
      formatToken,               // 令牌格式化函数
    }),
  );

  // 统一错误处理
  client.addResponseInterceptor(
    errorMessageResponseInterceptor((msg: string, error) => {
      // 获取错误信息：优先使用响应中的 error 或 message 字段
      const responseData = error?.response?.data ?? {};
      const errorMessage = responseData?.error ?? responseData?.message ?? '';
      // 显示错误提示
      ElMessage.error(errorMessage || msg);
    }),
  );

  return client;
}

/**
 * 导出配置好的请求客户端实例
 *
 * requestClient: 主要请求客户端，配置了完整的拦截器和响应处理
 * baseRequestClient: 基础请求客户端，仅配置了基础 URL
 */
export const requestClient = createRequestClient(apiURL, {
  responseReturn: 'data',        // 直接返回响应数据部分
});

export const baseRequestClient = new RequestClient({ baseURL: apiURL });
